package com.smartalarmclock.Model;

import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.smartalarmclock.Model.Exceptions.DataEntityDoesNotExistException;
import com.smartalarmclock.Model.Exceptions.InvalidSaveDataEntityOperationException;
import com.smartalarmclock.Model.Exceptions.SMSMessageAlreadyExistsException;

final class SMSMessage extends ReferencedDataEntity implements ISMSMessage {

	// Database Constants
	
	public static final String SMSMessageTableName = "SMSMessage";
	
	private static final String c_SMSMessageColumnNameMessage = "Message";
	private static final String[] c_QueryAllColumns = new String[] { c_ColumnNameId, c_SMSMessageColumnNameMessage };
	
	// Members
	
	private String m_Message;
	
	// Constructors
	
	/**
	 * Constructor
	 * @param message the message string
	 */
	protected SMSMessage(String message) {
		super();
		m_Message = message;
	}
	
	/**
	 * Constructor
	 * @param id the id
	 * @param message the message string
	 */
	protected SMSMessage(int id, String message) {
		super(id);
		m_Message = message;
	}
	
	// ISMSMessage implementation
	
	/**
	 * @return the message string
	 */
	@Override
	public String GetMessage() {
		return m_Message;
	}
	
	// IDataEntity implementation
	
	@Override
	public void Refresh(Context context) throws DataEntityDoesNotExistException {
		SMSMessage tempMessage = GetSMSMessageById(context, GetId());
		m_Message = tempMessage.GetMessage();
	}
	
	/**
	 * Saves the instance in the database
	 * @throws SMSMessageAlreadyExistsException if a SMSMessage with the message string already exists.
	 */
	@Override
	public void Save(Context context) throws InvalidSaveDataEntityOperationException {
		if (IsNewInstance() && TryGetSMSMessageByMessageString(context, m_Message) != null) {
			throw new SMSMessageAlreadyExistsException(m_Message);
		}
		
		super.Save(context);
	}
	
	// Public Methods
	
	/**
	 * @return the CREATE TABLE statement of the SMSMessage table
	 */
	static String GetSqlStatementCreateSMSMessageTable() {
		return "CREATE TABLE " + SMSMessageTableName + " (" +
				c_ColumnNameId + 				" INTEGER PRIMARY KEY, " +
				c_SMSMessageColumnNameMessage + " TEXT NOT NULL)";
	}
	
	/**
	 * @return the DROP TABLE statement of the SMSMessage table
	 */
	static String GetSqlStatementDropSMSMessageTable() {
		return "DROP TABLE IF EXISTS " + SMSMessageTableName;
	}
	
	/**
	 * Queries the DB for a SMSMessage entity with the matching id
	 * @param context the context of the request 
	 * @param id the id to query for
	 * @return the matching SMSMessage instance
	 * @throws DataEntityDoesNotExistException if the matching SMSMessage does not exist
	 */
	static SMSMessage GetSMSMessageById(Context context, int id) throws DataEntityDoesNotExistException {
		return GetSingleSMSMessage(
			context,
			c_ColumnNameId + "=" + id);
	}
	
	/**
	 * Queries the DB for a SMSMessage entity with the matching id
	 * @param context the context of the request 
	 * @param id the id to query for
	 * @return the matching SMSMessage instance, or null if does not exist
	 */
	static SMSMessage TryGetSMSMessageById(Context context, int id) {
		try {
			return GetSMSMessageById(context, id);
		}
		catch (DataEntityDoesNotExistException e) {
			return null;
		}
	}
	
	/**
	 * Queries the DB for a SMSMessage entity with the matching message string
	 * @param context the context of the request 
	 * @param message the message to query for
	 * @return the matching SMSMessage instance
	 * @throws DataEntityDoesNotExistException if the matching SMSMessage does not exist
	 */
	static SMSMessage GetSMSMessageByMessageString(Context context, String message) throws DataEntityDoesNotExistException {
		return GetSingleSMSMessage(
			context,
			c_SMSMessageColumnNameMessage + " LIKE \"" + message + "\"");
	}
	
	/**
	 * Queries the DB for a SMSMessage entity with the matching message string
	 * @param context the context of the request 
	 * @param message the message to query for
	 * @return the matching SMSMessage instance, or null if does not exist
	 */
	static SMSMessage TryGetSMSMessageByMessageString(Context context, String message) {
		try {
			return GetSMSMessageByMessageString(context, message);
		}
		catch (DataEntityDoesNotExistException e) {
			return null;
		}
	}
	
	/**
	 * Queries the DB for all SMSMessages
	 * @param context the context of the request 
	 * @return a set of all SMSMessages
	 */
	static Set<ISMSMessage> GetAllSMSMessages(Context context) {
		SQLiteDatabase db = OpenDBForReading(context);
		Cursor cursor = db.query(
			SMSMessageTableName,
			c_QueryAllColumns,
			null, null, null, null, null);
		
		Set<ISMSMessage> allMessages = new HashSet<ISMSMessage>();
		while (cursor.moveToNext()) {
			allMessages.add(CreateSMSMessageFromCursor(context, cursor));
		}
		
		return allMessages;
	}
	
	// Private Methods
	
	/**
	 * Queries a single SMSMessage entity from the DB.
	 * @param context the context of the request (the request Activity)
	 * @param whereClause the where clause for the query
	 * @return the matching single SMSMessage entity
	 * @throws DataEntityDoesNotExistException if the matching entity does not exist
	 */
	private static SMSMessage GetSingleSMSMessage(Context context, String whereClause) throws DataEntityDoesNotExistException {
		SQLiteDatabase db = OpenDBForReading(context);
		Cursor cursor = db.query(
			SMSMessageTableName,
			c_QueryAllColumns,
			whereClause,
			null, null, null, null);
		
		try {
			if (!cursor.moveToFirst()) {
				throw new DataEntityDoesNotExistException(SMSMessage.class, whereClause);
			}
			
			return CreateSMSMessageFromCursor(context, cursor);
		}
		finally {
			cursor.close();
			db.close();
		}
	}

	/**
	 * Creates a new SMSMessage instance from the values in the cursor 
	 * @param context the context of the request
	 * @param cursor the cursor holding the values.
	 * @return the matching SMSMessage instance.
	 */
	private static SMSMessage CreateSMSMessageFromCursor(Context context, Cursor cursor) {
		int id = cursor.getInt(cursor.getColumnIndex(c_ColumnNameId));
		String message = cursor.getString(cursor.getColumnIndex(c_SMSMessageColumnNameMessage));
		return new SMSMessage(id, message);
	}
	
	// DataEntity implementation
	
	@Override
	protected Hashtable<String, ContentValues> GetRecordValues() {
		ContentValues values = new ContentValues();
		values.put(c_SMSMessageColumnNameMessage, m_Message);
		
		Hashtable<String, ContentValues> valuesTable = new Hashtable<String, ContentValues>();
		valuesTable.put(SMSMessageTableName, values);
		return valuesTable;
	}
	
	@Override
	protected Set<String> GetTableNames() {
		Set<String> tableNames = new HashSet<String>();
		tableNames.add(SMSMessageTableName);
		return tableNames;
	}
}
